#include "common.h"
#include "base.h"
#include "configtable.h"
#include <iostream>
#include <string>
#include <fstream>
#include <algorithm>

void Configtable::load_config(std::string datadir) {
    std::string site_bandwidth_csv = datadir + "/site_bandwidth.csv";
    std::string qos_csv = datadir + "/qos.csv";
    std::string config_ini = datadir + "/config.ini";
    std::string demand_csv = datadir + "/demand.csv";

    std::ifstream infile;
    std::string line;
    std::vector<std::string> sp;

    // 读入qos表，生成cid与sid的list和map，以及生成qos矩阵
    infile.open(qos_csv);
    std::getline(infile, line);
    sp = split(line, ",");
    c_num = sp.size() - 1;
    for (int i = 1; i < int(sp.size()); i++) {
        cid_list.push_back(sp[i]);
        cid_index[sp[i]] = i - 1;
    }

    int s_cnt = 0;
    while (!infile.eof()) {
        std::getline(infile, line);
        sp = split(line, ",");
        if (int(sp.size()) > 1) {
            sid_list.push_back(sp[0]);
            sid_index[sp[0]] = s_cnt;
            qos.push_back(std::vector<int>(c_num));
            for (int i = 1; i < int(sp.size()); i++) {
                qos[s_cnt][i - 1] = std::stoi(sp[i]);
            }
            s_cnt++;
        }
    }
    s_num = s_cnt;
    infile.close();

#ifdef DEBUG_CONFIG //打印qos表
    for (int i = -1; i < s_num; i++) {
        std::cout << "# ";
        for (int j = -1; j < c_num; j++) {
            if (i == -1 && j == -1) {
                std::cout << "    ";
            } else if (i == -1) {
                std::cout << " " << cid_list[j] << " ";
            } else if (j == -1) {
                std::cout << " " << sid_list[i] << " ";
            } else {
                std::cout << " " << qos[sid_index[sid_list[i]]][cid_index[cid_list[j]]] << " ";
            }
        }
        std::cout << std::endl;
    }
#endif

    // 读入bandwidth表格
    infile.open(site_bandwidth_csv);
    std::getline(infile, line);
    bandwidth = std::vector<int>(s_num);
    for (int i = 0; i < s_num; i++) {
        std::getline(infile, line);
        sp = split(line, ",");
        int index = sid_index[sp[0]];
        bandwidth[index] = std::stoi(sp[1]);
    }
    infile.close();

#ifdef DEBUG_CONFIG
    for (int i = 0; i < s_num; i++) {
        std::cout << sid_list[i] << " " << bandwidth[sid_index[sid_list[i]]] << std::endl;
    }
#endif

    // 读入config.ini
    infile.open(config_ini);
    std::getline(infile, line);
    std::getline(infile, line);
    sp = split(line, "=");
    qos_constraint = std::stoi(sp[1]);
    infile.close();
    
#ifdef DEBUG_CONFIG
    std::cout << qos_constraint << std::endl;
#endif

   // 读取demand.csv
    infile.open(demand_csv);
    std::getline(infile, line);
    sp = split(line, ",");
    std::vector<std::string> cid_list_tmp;
    std::vector<std::vector<int>> bw_tmp(s_num);
    for (int i = 1; i < int(sp.size()); i++) {
        cid_list_tmp.push_back(sp[i]);
    }
    int line_cnt = 0;
    while (!infile.eof()) {
        std::getline(infile, line);
        sp = split(line, ",");
        if (int(sp.size()) > 1) {
            std::vector<int> pre_sch_tmp(s_num, 0);
            for (int i = 1; i < int(sp.size()); i++) {
                int this_bw = std::stoi(sp[i]);
                int this_s_index = cid_index[cid_list_tmp[i - 1]];
                for (int j = 0; j < s_num; j++) {
                    if (qos[j][this_s_index] < qos_constraint) {
                        pre_sch_tmp[j] += this_bw;
                    }
                }
            }
            for (int i = 0; i < s_num; i++) {
                bw_tmp[i].push_back(pre_sch_tmp[i]);
            }
            line_cnt++;
        }
    }
    infile.close();
    for (int i = 0; i < s_num; i++) {
        sort(bw_tmp[i].rbegin(), bw_tmp[i].rend());
    }
    max_percent_5 = line_cnt * 0.05;
    // int hard_index = line_cnt * 0.6;
    // 0.6 612440
    // 0.5 660518
    for (int i = 0; i < s_num; i++) {
        max_percent_5_ratio.push_back((bw_tmp[i][max_percent_5]) / double(bandwidth[i]));
    }


    // 度排序
    std::vector<int> degree(s_num, 0);
    for (int i = 0; i < s_num; i++) {
        for (int j = 0; j < c_num; j++) {
            if (qos[i][j] < qos_constraint) {
                degree[i]++;
            }
        }
        degree_sort.push_back(i);
    }
    std::sort(degree_sort.begin(), degree_sort.end(), [&](int x, int y)->bool{return degree[x] < degree[y];});
    

#ifdef DEBUG_CONFIG
    for (int i = 0; i < s_num; i++) {
        std::cout << sid_list[degree_sort[i]] << " ";
        // std::cout << degree[degree_sort[i]] << " ";
    }
    std::cout << std::endl;
    for (int i = 0; i < s_num; i++) {
        std::cout << max_percent_5_ratio[i] << " ";
    }
    std::cout << std::endl;
    for (int i = 0; i < int(bw_tmp[0].size()); i++) {
        for (int j = 0; j < 3; j++) {
            std::cout << bw_tmp[j][i] << " ";
        }
        std::cout << std::endl;
    }
    std::cout << max_percent_5 << std::endl;
    for (int i = 0; i < int(every_bw.size()); i++) {
        std::cout << every_bw_index[i] << " ";
    }
    std::cout << std::endl;
    for (int i = 0; i < int(max_percent_5_flag.size()); i++) {
        std::cout << max_percent_5_flag[i] << " ";
    }
    std::cout << std::endl;
#endif

}

Configtable::Configtable(std::string datadir) {
    load_config(datadir);
}

int Configtable::get_cnum() {
    return c_num;
}

int Configtable::get_snum() {
    return s_num;
}

int Configtable::get_max_percent_5() {
    return max_percent_5;
}

std::vector<double> Configtable::get_max_percent_5_ratio() {
    return max_percent_5_ratio;
}

std::vector<std::string> Configtable::get_cid_list() {
    return cid_list;
}

std::vector<std::string> Configtable::get_sid_list() {
    return sid_list;
}

std::string Configtable::get_cid(int index) {
    return cid_list[index];
}

std::string Configtable::get_sid(int index) {
    return sid_list[index];
}

int Configtable::get_cid_index(std::string cid) {
    return cid_index[cid];
}

int Configtable::get_sid_index(std::string sid) {
    return sid_index[sid];
}

int Configtable::get_bandwidth(std::string sid) {
    return bandwidth[sid_index[sid]];
}

int Configtable::get_bandwidth(int sid_index) {
    return bandwidth[sid_index];
}

bool Configtable::check_bandwidth(std::string sid, int bw) {
    return bw <= bandwidth[sid_index[sid]];
}

bool Configtable::check_bandwidth(int sid_index, int bw) {
    return bw <= bandwidth[sid_index];
}

int Configtable::get_qos_constraint() {
    return qos_constraint;
}

int Configtable::get_qos(std::string sid, std::string cid) {
    return qos[sid_index[sid]][cid_index[cid]];
}

int Configtable::get_qos(std::string sid, int cid_index) {
    return qos[sid_index[sid]][cid_index];
}

int Configtable::get_qos(int sid_index, std::string cid) {
    return qos[sid_index][cid_index[cid]];
}

int Configtable::get_qos(int sid_index, int cid_index) {
    return qos[sid_index][cid_index];
}

bool Configtable::check_qos(std::string sid, std::string cid) {
    return qos[sid_index[sid]][cid_index[cid]] < qos_constraint;
}

bool Configtable::check_qos(std::string sid, int cid_index) {
    return qos[sid_index[sid]][cid_index] < qos_constraint;
}

bool Configtable::check_qos(int sid_index, std::string cid) {
    return qos[sid_index][cid_index[cid]] < qos_constraint;
}

bool Configtable::check_qos(int sid_index, int cid_index) {
    return qos[sid_index][cid_index] < qos_constraint;
}

std::vector<int> Configtable::get_degree_sort() {
    return degree_sort;
}


Configtable::~Configtable() {

}
